// 子组件表
var buildComponents = {}

/**
 * MVVM Library
 * className: buildPage
 * version: 0.0.1
 * nextUpdate: NaN
 * updateTime: 2021/05/28
 * @Author 洛水天依 <luotianyiovo@gmail.com>
 */
class buildPage {
    options = {
        name: '',
        // domID节点
        dom: '',
        // 数据模板
        template: '',
        // 数据源
        data: {},
        // 渲染结束后回调
        created: () => {},
        methods: {},
        // 前置回调
        beforeAction: () => {},
        // 子组件列表
        components: {}
    }
    events = ['click', 'input', 'change', 'blur']
    // 当前节点数据
    data = {}
    // 父节点传递数据
    props = {}

    // dom对象
    domObject = HTMLElement
    // 虚拟节点列表
    vNode = []
    // 虚拟节点对象
    h = VNode

    // 虚拟节点生成的DOM
    createDom = ''
    // 需要挂载的DOM
    mountDom = ''
    parent = null

    constructor (options = {
        // 组件名称
        name: '',
        template: '',
        dom: '',
        components: {},
        // 创建DOM 结束后回调
        created: () => {},
        methods: {},
        // 创建DOM前回调
        beforeAction: () => {}
    }) {
        // 处理子组件
        let components = {}
        for (const optionsKey in options.components) {
            components[optionsKey.toLocaleUpperCase()] = options.components[optionsKey]
        }
        buildComponents = options.components = components

        this.options = Object.assign(this.options, options)
        this.domObject = this.options.template !== '' ?
            new DOMParser().parseFromString(this.options.template, 'text/html').body.firstElementChild
            : document.querySelector(this.options.dom)
        this.data = options.data
        this.options.beforeAction.apply(this)
    }

    initialization() {
        // 遍历构建虚拟节点
        this.vNode = this.traverseDomTree()
        this.proxyInterceptionModel(this.data)
        this.data = this.createProxy(this.data)
        // 创建后DOM
        this.createDom = new this.h('div', {
            owningNode: this
        }).traverseVNodeCreatDom(this.vNode)
        this.options.created.apply(this, [this.mountDom])
        return this
    }

    // 更新DOM节点
    initializationDomAndUpdate() {
        this.createDom = this.traverseDomTree().traverseVNodeCreatDom()
        this.mount(this.options.dom || this.mountDom, false)
    }

    // 遍历节点生成虚拟节点
    traverseDomTree(dom = null) {
        dom = dom || this.domObject
        let domConfig = {
            children: [],
            content: dom.firstChild?.nodeValue,
            row: dom.innerHTML,
            on: this.events,
            dom: dom,
            parent: this.parent,
            owningNode: this
        }
        dom.childNodes.forEach((vdom, key) => {
            if (vdom.nodeType !== 3 && vdom.tagName !== undefined) {
                let cDom = this.options.components[vdom.tagName] || ''

                if (cDom !== '') {
                    // 写入列表
                    domConfig.children.push(new Component(
                        cDom.setParent(this).initialization(), this, vdom
                    ).setData(cDom.data))
                } else {
                    domConfig.children.push(this.traverseDomTree(vdom))
                }
            }
        })
        // 解析当前节点绑定指令
        return new this.h(
            dom.tagName, domConfig
        )
    }

    // 拦截模型数据更新
    proxyInterceptionModel(object) {
        if (typeof object === 'object') {
            for (let index in object) {
                if (typeof object[index] === 'object') {
                    object[index] = this.proxyInterceptionModel(object[index])
                }
            }
        } else if (Array.isArray(object)) {
            object = object.map(obj => {
                return this.proxyInterceptionModel(obj)
            })
        }
        object = this.createProxy(object)
        return object
    }

    // 创建拦截
    createProxy(object) {

        if (object === null) return object

        return new Proxy(object, {
            get: (target, key, receiver) => {
                return Reflect.get(target, key);
            },
            set: (target, key, value, receiver) => {
                key = key.split(':')
                const change = Reflect.set(target, key[0], value)
                // 验证更新是否需要更新DOM
                if (key.length === 1 || (key.length > 1 && key[1] !== 'noUpdate')) {
                    // 刷新节点
                    this.initializationDomAndUpdate()
                }
                // if (value instanceof Object) {
                //     this.proxyInterceptionModel(target[key])
                // }
                return change
            }
        })
    }

    setParent (parent) {
        this.parent = parent
        return this
    }

    // 引入扩展
    use(options = {}) {
        if (options.constructor.name !== 'Object') {
            this[options.constructor.name] = options
            return this
        }

        for (const optionsKey in options) {
            this[options[optionsKey].constructor.name] = options[optionsKey]
        }
        return this
    }

    // 挂载节点
    mount(dom = '', remove = true) {
        // 验证是否有上级节点
        if (this.parent !== null) return this

        if (remove) this.initialization()
        this.mountDom = dom || this.options.dom
        if (this.mountDom !== this.options.dom && remove && this.options.dom !== '') {
            document.querySelector(this.options.dom)?.remove()
        }
        dom = document.querySelector(this.mountDom)
        if (dom === null) dom = document.querySelector(`${this.createDom.tagName}[rootid='${this.mountDom}']`)
        this.createDom.setAttribute('rootId', this.mountDom)
        if (dom) {
            // 替换dom节点
            dom.replaceWith(this.createDom)
        }
        return this
    }

    // 触发节点事件
    emit(event, ...args) {
        if (this.parent?.options.methods[event] === undefined) return
        this.parent?.options.methods[event].apply(this.parent, ...args)
    }
}
